<?php

namespace App\Http\Controllers\Tenant;

use App\Http\Controllers\Controller;
use App\Models\Task;
use App\Models\TaskApplication;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use ZipArchive;

class TaskApplicationController extends Controller
{
    /**
     * 获取任务报名列表
     */
    public function index(Request $request, $taskId)
    {
        $tenantId = $request->user()->tenant_id;

        $task = Task::where('tenant_id', $tenantId)
                   ->findOrFail($taskId);

        $query = TaskApplication::with(['freelancer', 'processor'])
            ->where('tenant_id', $tenantId)
            ->where('task_id', $taskId);

        if ($request->filled('name')) {
            $query->where('name', 'like', '%' . $request->name . '%');
        }

        if ($request->filled('phone')) {
            $query->where('phone', 'like', '%' . $request->phone . '%');
        }

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        $allowedSortBy = ['name', 'phone', 'status', 'created_at'];
        $sortBy = $request->get('sort_by', 'name');
        if (!in_array($sortBy, $allowedSortBy, true)) {
            $sortBy = 'name';
        }
        $sortOrder = strtolower($request->get('sort_order', 'asc')) === 'desc' ? 'desc' : 'asc';

        $applications = $query->orderBy($sortBy, $sortOrder)
            ->paginate(
                (int) $request->get('per_page', 15),
                ['*'],
                'page',
                (int) max(1, (int) $request->get('page', 1))
            );

        $applications->getCollection()->transform(function (TaskApplication $application) {
            return [
                'id' => $application->id,
                'name' => $application->name,
                'phone' => $application->phone,
                'id_number' => $application->id_card,
                'bank_card' => $this->getApplicationBankAccount($application),
                'status' => $application->status,
                'status_label' => $this->mapApplicationStatus($application->status),
                'sign_status' => $this->resolveContractStatus($application),
                'contact_status' => data_get($application, 'contact_status', ''),
                'created_at' => optional($application->created_at)->format('Y-m-d H:i:s'),
            ];
        });

        return response()->json([
            'code' => 0,
            'message' => '获取报名列表成功',
            'data' => [
                'task' => $task,
                'applications' => $applications
            ]
        ]);
    }

    /**
     * 获取报名详情
     */
    public function show(Request $request, $taskId, $applicationId)
    {
        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $application = TaskApplication::where('task_id', $taskId)
                                     ->with(['freelancer', 'processor'])
                                     ->findOrFail($applicationId);

        return response()->json([
            'success' => true,
            'data' => [
                'task' => $task,
                'application' => $application
            ]
        ]);
    }

    /**
     * 批准报名
     */
    public function approve(Request $request, $taskId, $applicationId)
    {
        $validator = Validator::make($request->all(), [
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => '参数验证失败',
                'errors' => $validator->errors()
            ], 422);
        }

        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $application = TaskApplication::where('task_id', $taskId)
                                     ->where('status', 'pending')
                                     ->findOrFail($applicationId);

        $application->approve($request->user()->id, $request->notes);

        return response()->json([
            'code' => 0,
            'message' => '报名已批准',
            'data' => $application->fresh(['freelancer', 'processor'])
        ]);
    }

    /**
     * 拒绝报名
     */
    public function reject(Request $request, $taskId, $applicationId)
    {
        $validator = Validator::make($request->all(), [
            'reason' => 'required|string|max:500',
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'code' => 422,
                'message' => '参数验证失败',
                'data' => $validator->errors()
            ], 422);
        }

        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $application = TaskApplication::where('task_id', $taskId)
                                     ->where('status', 'pending')
                                     ->findOrFail($applicationId);

        $application->reject($request->user()->id, $request->reason, $request->notes);

        return response()->json([
            'code' => 0,
            'message' => '报名已拒绝',
            'data' => $application->fresh(['freelancer', 'processor'])
        ]);
    }

    /**
     * 设置离岗
     */
    public function dimission(Request $request, $taskId, $applicationId)
    {
        $validator = Validator::make($request->all(), [
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'code' => 422,
                'message' => '参数验证失败',
                'data' => $validator->errors()
            ], 422);
        }

        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $application = TaskApplication::where('task_id', $taskId)
                                     ->findOrFail($applicationId);

        if (!in_array($application->status, ['approved', 'completed'], true)) {
            return response()->json([
                'code' => 400,
                'message' => '当前状态不可设置为离岗',
                'data' => null,
            ], 400);
        }

        $application->markDimission($request->user()->id, $request->notes);

        return response()->json([
            'code' => 0,
            'message' => '已标记为离岗',
            'data' => $application->fresh(['freelancer', 'processor'])
        ]);
    }

    /**
     * 批量处理报名
     */
    public function batchAction(Request $request, $taskId)
    {
        $validator = Validator::make($request->all(), [
            'application_ids' => 'required|array|min:1',
            'application_ids.*' => 'integer|exists:task_applications,id',
            'action' => 'required|in:approve,reject',
            'reason' => 'required_if:action,reject|string|max:500',
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => '参数验证失败',
                'errors' => $validator->errors()
            ], 422);
        }

        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $applications = TaskApplication::where('task_id', $taskId)
                                      ->where('status', 'pending')
                                      ->whereIn('id', $request->application_ids)
                                      ->get();

        $successCount = 0;
        $errors = [];

        foreach ($applications as $application) {
            try {
                if ($request->action === 'approve') {
                    $application->approve($request->user()->id, $request->notes);
                } else {
                    $application->reject($request->user()->id, $request->reason, $request->notes);
                }
                $successCount++;
            } catch (\Exception $e) {
                $errors[] = "报名ID {$application->id} 处理失败：" . $e->getMessage();
            }
        }

        return response()->json([
            'success' => true,
            'message' => "批量操作完成，成功处理 {$successCount} 个报名",
            'data' => [
                'success_count' => $successCount,
                'total_count' => count($applications),
                'errors' => $errors
            ]
        ]);
    }

    /**
     * 获取报名统计信息
     */
    public function statistics(Request $request, $taskId)
    {
        $task = Task::where('tenant_id', $request->user()->tenant_id)
                   ->findOrFail($taskId);

        $stats = [
            'total' => TaskApplication::where('task_id', $taskId)->count(),
            'pending' => TaskApplication::where('task_id', $taskId)->where('status', 'pending')->count(),
            'approved' => TaskApplication::where('task_id', $taskId)->where('status', 'approved')->count(),
            'rejected' => TaskApplication::where('task_id', $taskId)->where('status', 'rejected')->count(),
        ];

        return response()->json([
            'success' => true,
            'data' => $stats
        ]);
    }

    /**
     * 导出成员列表
     */
    public function export(Request $request, $taskId)
    {
        $tenantId = $request->user()->tenant_id;

        Task::where('tenant_id', $tenantId)->findOrFail($taskId);

        $applicationsQuery = TaskApplication::with('freelancer')
            ->where('tenant_id', $tenantId)
            ->where('task_id', $taskId);

        if ($request->filled('name')) {
            $applicationsQuery->where('name', 'like', '%' . $request->name . '%');
        }

        if ($request->filled('phone')) {
            $applicationsQuery->where('phone', 'like', '%' . $request->phone . '%');
        }

        if ($request->filled('status')) {
            $applicationsQuery->where('status', $request->status);
        }

        $applications = $applicationsQuery->orderBy('created_at', 'desc')->get();

        $headers = ['姓名', '手机号', '身份证号', '银行卡号', '报名状态', '签约状态'];

        $rows = $applications->map(function (TaskApplication $application) {
            return [
                '姓名' => $application->name,
                '手机号' => $application->phone,
                '身份证号' => $application->id_card,
                '银行卡号' => $this->getApplicationBankAccount($application),
                '报名状态' => $this->mapApplicationStatus($application->status),
                '签约状态' => $this->resolveContractStatus($application),
            ];
        })->toArray();

        $content = $this->generateXlsx($headers, $rows);

        $filename = sprintf('成员列表_%s.xlsx', now()->format('YmdHis'));

        return response()->streamDownload(function () use ($content) {
            echo $content;
        }, $filename, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        ]);
    }

    /**
     * 导出结算模板
     */
    public function exportSettlementTemplate(Request $request, $taskId)
    {
        $tenantId = $request->user()->tenant_id;

        Task::where('tenant_id', $tenantId)->findOrFail($taskId);

        $applicationsQuery = TaskApplication::with('freelancer')
            ->where('tenant_id', $tenantId)
            ->where('task_id', $taskId);

        if ($request->filled('name')) {
            $applicationsQuery->where('name', 'like', '%' . $request->name . '%');
        }

        if ($request->filled('phone')) {
            $applicationsQuery->where('phone', 'like', '%' . $request->phone . '%');
        }

        if ($request->filled('status')) {
            $applicationsQuery->where('status', $request->status);
        }

        $applications = $applicationsQuery->orderBy('created_at', 'desc')->get();

        $headers = ['姓名', '手机号', '身份证号', '银行卡号', '发放金额（元）', '款项备注（选填）'];

        $rows = $applications->map(function (TaskApplication $application) {
            return [
                '姓名' => $application->name,
                '手机号' => $application->phone,
                '身份证号' => $application->id_card,
                '银行卡号' => $this->getApplicationBankAccount($application),
                '发放金额（元）' => '',
                '款项备注（选填）' => '',
            ];
        })->toArray();

        $content = $this->generateXlsx($headers, $rows);

        $filename = sprintf('结算模板_%s.xlsx', now()->format('YmdHis'));

        return response()->streamDownload(function () use ($content) {
            echo $content;
        }, $filename, [
            'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        ]);
    }

    private function generateXlsx(array $headers, array $rows): string
    {
        $sheetXml = $this->buildSheetXml($headers, $rows);

        $workbookXml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <sheets>
    <sheet name="Sheet1" sheetId="1" r:id="rId1" />
  </sheets>
</workbook>
XML;

        $workbookRelsXml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml" />
</Relationships>
XML;

        $relsXml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
  <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml" />
</Relationships>
XML;

        $contentTypesXml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
  <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
  <Default Extension="xml" ContentType="application/xml" />
  <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />
  <Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />
</Types>
XML;

        $tempFile = tempnam(sys_get_temp_dir(), 'xlsx_');
        $zip = new ZipArchive();

        if ($zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== true) {
            throw new \RuntimeException('无法创建导出文件');
        }

        $zip->addFromString('[Content_Types].xml', $contentTypesXml);
        $zip->addFromString('_rels/.rels', $relsXml);
        $zip->addFromString('xl/_rels/workbook.xml.rels', $workbookRelsXml);
        $zip->addFromString('xl/workbook.xml', $workbookXml);
        $zip->addFromString('xl/worksheets/sheet1.xml', $sheetXml);
        $zip->close();

        $content = file_get_contents($tempFile) ?: '';
        @unlink($tempFile);

        return $content;
    }

    private function buildSheetXml(array $headers, array $rows): string
    {
        $columnCount = max(count($headers), 1);
        $rowCount = count($rows) + 1; // 包含表头行

        $lastColumn = $this->columnLetter($columnCount);
        $lastRow = max($rowCount, 1);
        $dimension = sprintf('A1:%s%d', $lastColumn, $lastRow);

        $xml = '<?xml version="1.0" encoding="UTF-8"?>';
        $xml .= '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">';
        $xml .= '<dimension ref="' . $dimension . '" />';
        $xml .= '<sheetViews><sheetView workbookViewId="0" /></sheetViews>';
        $xml .= '<sheetFormatPr defaultRowHeight="15" />';
        $xml .= '<sheetData>';

        $xml .= $this->buildRowXml(1, $headers);

        foreach ($rows as $index => $row) {
            $orderedRow = array_map(function ($header) use ($row) {
                return $row[$header] ?? '';
            }, $headers);
            $xml .= $this->buildRowXml($index + 2, $orderedRow);
        }

        $xml .= '</sheetData>';
        $xml .= '</worksheet>';

        return $xml;
    }

    private function buildRowXml(int $rowNumber, array $values): string
    {
        $cells = [];

        foreach ($values as $columnIndex => $value) {
            $cellReference = $this->columnLetter($columnIndex + 1) . $rowNumber;
            $escapedValue = $this->escapeXml((string) $value);
            $cells[] = '<c r="' . $cellReference . '" t="inlineStr"><is><t>' . $escapedValue . '</t></is></c>';
        }

        return '<row r="' . $rowNumber . '">' . implode('', $cells) . '</row>';
    }

    private function columnLetter(int $columnNumber): string
    {
        $letter = '';

        while ($columnNumber > 0) {
            $mod = ($columnNumber - 1) % 26;
            $letter = chr(65 + $mod) . $letter;
            $columnNumber = (int) (($columnNumber - $mod - 1) / 26);
        }

        return $letter ?: 'A';
    }

    private function escapeXml(string $value): string
    {
        return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }

    private function mapApplicationStatus(?string $status): string
    {
        $map = [
            'pending' => '待处理',
            'approved' => '已录用',
            'rejected' => '已拒绝',
            'completed' => '已完成',
            'cancelled' => '已取消',
            'dimission' => '已离岗',
        ];

        return $map[$status] ?? '未知状态';
    }

    private function resolveContractStatus(TaskApplication $application): string
    {
        $explicitStatus = data_get($application, 'contract_status');

        if ($explicitStatus) {
            $map = [
                'signed' => '已签约',
                'unsigned' => '未签约',
                'in_progress' => '签约中',
                'pending' => '签约中',
            ];

            return $map[$explicitStatus] ?? $explicitStatus;
        }

        return $this->mapContractStatus(
            data_get($application, 'freelancer.status'),
            $application->status
        );
    }

    private function mapContractStatus(?string $freelancerStatus, ?string $applicationStatus): string
    {
        if ($applicationStatus === 'completed') {
            return '已签约';
        }

        $map = [
            'active' => '已签约',
            'inactive' => '未签约',
        ];

        return $map[$freelancerStatus] ?? '未签约';
    }

    private function getApplicationBankAccount(TaskApplication $application): string
    {
        $candidates = [
            data_get($application, 'bank_account'),
            data_get($application, 'bank_card'),
            data_get($application, 'bank_no'),
            optional($application->freelancer)->bank_account,
        ];

        foreach ($candidates as $value) {
            if (!empty($value)) {
                return (string) $value;
            }
        }

        return '';
    }
}
